using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using InvadersEx02.ObjectModel;

namespace InvadersEx02
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class InvadersGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager m_Graphics;
        SpriteBatch m_SpriteBatch;
        IList<Enemy1> m_Enemy1List;
        IList<Enemy2> m_Enemy2List;
        IList<Enemy3> m_Enemy3List;

        public InvadersGame()
        {
            m_Graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            Components.Add(new Background(this));
            Components.Add(new Ship(this));

            createEnemies();
        }

        private void createEnemies()
        {
            m_Enemy1List = new List<Enemy1>();
            m_Enemy2List = new List<Enemy2>();
            m_Enemy3List = new List<Enemy3>();

            for (int i = 0; i < 9; i++)
            {
                Enemy1 enemy1 = new Enemy1(this);
                m_Enemy1List.Add(enemy1);
                Components.Add(enemy1);

                Enemy2 enemy2 = new Enemy2(this);
                m_Enemy2List.Add(enemy2);
                Components.Add(enemy2);

                Enemy3 enemy3 = new Enemy3(this);
                m_Enemy3List.Add(enemy3);
                Components.Add(enemy3);
            }

            for (int i = 0; i < 9; i++)
            {
                Enemy2 enemy2 = new Enemy2(this);
                m_Enemy2List.Add(enemy2);
                Components.Add(enemy2);

                Enemy3 enemy3 = new Enemy3(this);
                m_Enemy3List.Add(enemy3);
                Components.Add(enemy3);
            }
        }

        private void initEnemies()
        {
            const float k_DistanceBetweenEnemies = (float)(32 * 0.6);

            for (int i = 0; i < m_Enemy1List.Count; i++)
            {
                m_Enemy1List[i].Position =
                    new Vector2((i * k_DistanceBetweenEnemies) + (i * m_Enemy1List[i].Width), m_Enemy1List[i].Height * 3);
                m_Enemy1List[i].LeftDownJumpBound = m_Enemy1List[i].Position.X;
                m_Enemy1List[i].RightDownJumpBound =
                    GraphicsDevice.Viewport.Width - ((9 - i) * m_Enemy1List[i].Width) - ((9 - i - 1) * k_DistanceBetweenEnemies);
                m_Enemy1List[i].EnemyReachedBottom += new EventHandler(InvadersGame_EnemyReachedBottom);
            }
            
            for (int i = 0; i < m_Enemy2List.Count; i++)
            {
                float distanceFromTop = i < 9 ?
                    (float)((m_Enemy2List[i].Height * 4) + (k_DistanceBetweenEnemies)) : (float)((m_Enemy2List[i].Height * 5) + (k_DistanceBetweenEnemies * 2));
                float distanceFromLeft = i < 9 ?
                    (float)((i * k_DistanceBetweenEnemies) + (i * m_Enemy2List[i].Width)) : (float)(((i - 9) * k_DistanceBetweenEnemies) + ((i - 9) * m_Enemy2List[i].Width));
                m_Enemy2List[i].Position = new Vector2(distanceFromLeft, distanceFromTop);
                m_Enemy2List[i].LeftDownJumpBound = m_Enemy2List[i].Position.X;
                m_Enemy2List[i].RightDownJumpBound = i < 9 ?
                    GraphicsDevice.Viewport.Width - ((9 - i) * m_Enemy2List[i].Width) - ((9 - i - 1) * k_DistanceBetweenEnemies) :
                    GraphicsDevice.Viewport.Width - ((9 - i + 9) * m_Enemy2List[i].Width) - ((9 - i + 9 - 1) * k_DistanceBetweenEnemies);
                m_Enemy2List[i].EnemyReachedBottom += new EventHandler(InvadersGame_EnemyReachedBottom);
            }
            
            for (int i = 0; i < m_Enemy3List.Count; i++)
            {
                float distanceFromTop = i < 9 ?
                    (float)((m_Enemy3List[i].Height * 6) + (k_DistanceBetweenEnemies * 3)) : (float)((m_Enemy3List[i].Height * 7) + (k_DistanceBetweenEnemies * 4));
                float distanceFromLeft = i < 9 ?
                    (float)((i * k_DistanceBetweenEnemies) + (i * m_Enemy3List[i].Width)) : (float)(((i - 9) * k_DistanceBetweenEnemies) + ((i - 9) * m_Enemy3List[i].Width));
                m_Enemy3List[i].Position = new Vector2(distanceFromLeft, distanceFromTop);
                m_Enemy3List[i].LeftDownJumpBound = m_Enemy3List[i].Position.X;
                m_Enemy3List[i].RightDownJumpBound = i < 9 ?
                    GraphicsDevice.Viewport.Width - ((9 - i) * m_Enemy3List[i].Width) - ((9 - i - 1) * k_DistanceBetweenEnemies) :
                    GraphicsDevice.Viewport.Width - ((9 - i + 9) * m_Enemy3List[i].Width) - ((9 - i + 9 - 1) * k_DistanceBetweenEnemies);
                m_Enemy3List[i].EnemyReachedBottom += new EventHandler(InvadersGame_EnemyReachedBottom);
            }
        }

        private void InvadersGame_EnemyReachedBottom(object sender, EventArgs e)
        {
            foreach (GameComponent component in Components)
            {
                component.Enabled = false;
            }

            System.Windows.Forms.MessageBox.Show("Game Over!", "Invaders");
            Exit();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            this.Window.Title = "Invaders";

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            m_SpriteBatch = new SpriteBatch(GraphicsDevice);

            foreach (IGameComponent component in Components)
            {
                Enemy enemy = component as Enemy;
                if (enemy != null)
                {
                    enemy.SpriteBatch = m_SpriteBatch;
                }
            }

            initEnemies();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            m_SpriteBatch.Begin();
            base.Draw(gameTime);
            m_SpriteBatch.End();
        }
    }
}
